# Core Model for check the identity. The password is hashed.Propeties password and password_confirmation is just for creat a new user.

class User < ActiveRecord::Base
  require 'digest/sha2'
  USER_NAME_LENGTH_MIN = 3
  USER_NAME_LENGTH_MAX = 20
  USER_NAME_LENGTH_RANGE = USER_NAME_LENGTH_MIN .. USER_NAME_LENGTH_MAX
  PASSWORD_LENGTH_MIN = 6
  PASSWORD_LENGTH_MAX = 20
  PASSWORD_LENGTH_RANGE = PASSWORD_LENGTH_MIN .. PASSWORD_LENGTH_MAX
  REMEMBER_LIFETIME = 1.week

  ## Property
  has_one    :profile,
             :dependent => :destroy
  has_many   :articles,
             :dependent => :destroy,
             :order => 'created_at DESC'
  # virtual property
  attr_reader   :password
  attr_accessor :password_confirmation

  ## The user's recent article, last post.
  def recent_article
    Article.find_by_user_id( self, :limit => 1, :order => 'created_at DESC' )
  end

  # Validates
  validates :username,
            :presence => true,
            :uniqueness => true,
            :length => USER_NAME_LENGTH_RANGE
  validates :password, 
            :length => PASSWORD_LENGTH_RANGE, 
            :confirmation => true,
            :if => :password_present?
  validates :hashed_password, :presence => true
  validate  :profile_present

  # Filter
  before_destroy :root_can_not_be_destroy


  ## already logged in?
  def logged? session
    session[:user_id] == self
  end

  ## log the user in
  def login! session
    session[:user_id] = self
  end

  ## log the user out
  def logout! session
    session[:user_id] = nil
  end

  ## Password write method, generate hashed password.
  def password=(password)
    @password = password

    if password.present?
      generate_salt
      self.hashed_password = self.class.encrypt(password, salt)
    end
  end

  ## Check the username and password. If authenticated return user object.
  def User.authenticate(username, password)
    if user = find_by_username(username)
      if user.hashed_password == encrypt(password, user.salt)
        user
      end
    end
  end

  def remember_me cookies
    self.remember_expires_at = REMEMBER_LIFETIME.from_now.utc
    self.remember_token = User.encrypt(rand.to_s + self.salt + rand.to_s, self.salt)
    self.save
    cookies[:auth_token] = { :value => self.remember_token, :expires => self.remember_expires_at }
  end

  def forget_me
    self.remember_expires_at = self.remember_token = nil
    self.save
  end

private
  def root_can_not_be_destroy
    if self.id == 1
      raise "Root Administrator can not be destroyed!"
    end
  end

  def User.encrypt(password, salt)
    Digest::SHA2.hexdigest(password + "republic" + salt)
  end

  def generate_salt
    self.salt = rand.to_s + self.object_id.to_s + rand.to_s
  end

  def profile_present
    if self.profile.nil?
      self.profile = Profile.new
    end
    true
  end
  
  def password_present?
    self.password.present?
  end
end
